package com.zxing.practice.config;

import com.zxing.practice.config.vo.LoginInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter  {


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    @SuppressWarnings(value = { "unchecked"})
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        // 从requert中取出信息
        if (Objects.nonNull(token) && token.startsWith(SysConstant.TOKEN_PREFIX)){
            token = token.replace(SysConstant.TOKEN_PREFIX, "").trim();
            if (!Objects.equals("", token)){
                Claims claims = Jwts.parser().setSigningKey(SysConstant.LOGIN_SECRET).parseClaimsJws(token).getBody();
                String tokenKey = (String)claims.get(SysConstant.TOKEN_KEY);
                Object obj = redisTemplate.opsForValue().get(SysConstant.TOKEN_KEY_HEADER + tokenKey);
                if (obj != null){
                    Map<String, Object> o = (Map<String, Object>) obj;
                    Long expireTime = (Long)o.get("expireTime");
                    Set<String> permissions = new HashSet<>((List<String>) o.get("permissions"));
                    Set<String> roleSigns = new HashSet<>((List<String>) o.get("roleSigns"));
                    long currentTime = System.currentTimeMillis();
                    if(expireTime - currentTime <= SysConstant.MILLIS_MINUTE_TEN){
                        LoginInfo loginInfo = new LoginInfo();
                        loginInfo.setRoleSigns(roleSigns);
                        loginInfo.setPermissions(permissions);
                        // 刷新jwt
                        loginInfo.setExpireTime(currentTime + SysConstant.MILLIS_MINUTE_ONE_HUNDRED_EIGHT);
                        redisTemplate.opsForValue().set(SysConstant.TOKEN_KEY_HEADER + tokenKey, loginInfo, SysConstant.ONE_HUNDRED_EIGHT, TimeUnit.MINUTES);
                    }
                    Set<GrantedAuthority> grantedAuthorities = roleSigns.stream().map(roleSign -> (GrantedAuthority) () -> roleSign).collect(Collectors.toSet());
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(SysConstant.TOKEN_KEY_HEADER + tokenKey, null, grantedAuthorities);
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        filterChain.doFilter(request, response);
    }
}
